package com.sean.community.service;

import com.sean.community.entity.User;
import com.sean.community.util.CommunityConstant;
import com.sean.community.util.RedisKeyUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SessionCallback;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
@SuppressWarnings("all")
public class FollowService implements CommunityConstant {
    private RedisTemplate<String, Object> redisTemplate;
    private UserService userService;

    @Autowired
    public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    @Autowired
    public void setUserService(UserService userService) {
        this.userService = userService;
    }

    // 关注某个实体
    public void follow(int userId, int entityType, int entityId){
        redisTemplate.execute(new SessionCallback<Object>() {
            @Override
            public Object execute(RedisOperations operations) throws DataAccessException {
                String followeeKey = RedisKeyUtil.getFolloweeKey(userId, entityType);
                String followerKey = RedisKeyUtil.getFollowerKey(entityType, entityId);
                operations.multi();     // 开启事务
                redisTemplate.opsForZSet().add(followeeKey, entityId, System.currentTimeMillis());
                redisTemplate.opsForZSet().add(followerKey, userId, System.currentTimeMillis());
                return operations.exec();  // 提交事务
            }
        });
    }

    // 取消关注某个实体
    public void unFollow(int userId, int entityType, int entityId){
        redisTemplate.execute(new SessionCallback<Object>() {
            @Override
            public Object execute(RedisOperations operations) throws DataAccessException {
                String followeeKey = RedisKeyUtil.getFolloweeKey(userId, entityType);
                String followerKey = RedisKeyUtil.getFollowerKey(entityType, entityId);
                operations.multi();     // 开启事务
                redisTemplate.opsForZSet().remove(followeeKey, entityId);
                redisTemplate.opsForZSet().remove(followerKey, userId);
                return operations.exec();  // 提交事务
            }
        });
    }

    // 查询某个用户关注的某类实体的数量
    @SuppressWarnings("all")
    public long findFolloweeCount(int userId, int entityType){
        String followeeKey = RedisKeyUtil.getFolloweeKey(userId, entityType);
        return redisTemplate.opsForZSet().zCard(followeeKey);
    }

    // 查询某个实体的粉丝的数量
    @SuppressWarnings("all")
    public long findFollowerCount(int entityType, int entityId){
        String followerKey = RedisKeyUtil.getFollowerKey(entityType, entityId);
        return redisTemplate.opsForZSet().zCard(followerKey);
    }

    // 查询当前用户是否关注该实体
    public boolean hasFollowed(int userId, int entityType, int entityId){
        String followeeKey = RedisKeyUtil.getFolloweeKey(userId, entityType);
        return redisTemplate.opsForZSet().score(followeeKey, entityId) != null;
    }

    // 查询某个用户关注的人
    public List<Map<String, Object>> findFollowees(int userId, int offset, int limit){
        // 从 Redis 中查找关注对象
        String followeeKey = RedisKeyUtil.getFolloweeKey(userId, ENTITY_TYPE_USER);
        // 无法将 Set<Object> 转为 Set<Integer>
        // Set<Integer> targetIds = redisTemplate.opsForZSet().reverseRange(followeeKey, offset, offset + limit - 1);
        Set<Object> targetIds = redisTemplate.opsForZSet().reverseRange(followeeKey, offset, offset + limit - 1);
        if(targetIds == null){
            return null;
        }
        List<Integer> targetIdList = new ArrayList<>();
        for (Object o : targetIds) {
            targetIdList.add(Integer.valueOf(String.valueOf(o)));   // 不能使用 （String）o
        }
        // 将关注对象封装（关注对象、关注时间）
        List<Map<String, Object>> list = new ArrayList<>();
        for(Integer targetUserId : targetIdList){
            Map<String, Object> map = new HashMap<>();
            // 关注对象
            User targetUser = userService.findUserById(targetUserId);
            map.put("targetUser", targetUser);
            // 关注时间
            Double score = redisTemplate.opsForZSet().score(followeeKey, targetUserId);
            assert score != null;
            map.put("followTime", new Date(score.longValue()));
            // 添加到关注对象列表
            list.add(map);
        }
        return list;
    }

    // 查询某个用户的粉丝
    public List<Map<String, Object>> findFollowers(int userId, int offset, int limit){
        // 从 Redis 中查找粉丝
        String followerKey = RedisKeyUtil.getFollowerKey(ENTITY_TYPE_USER, userId);
        Set<Object> followerIds = redisTemplate.opsForZSet().reverseRange(followerKey, offset, offset + limit - 1);
        if(followerIds == null){
            return null;
        }
        List<Integer> followerIdList = new ArrayList<>();
        for (Object o : followerIds) {
            followerIdList.add(Integer.valueOf(String.valueOf(o)));
        }
        // 将粉丝封装（粉丝、关注时间）
        List<Map<String, Object>> list = new ArrayList<>();
        for(Integer followerId : followerIdList){
            Map<String, Object> map = new HashMap<>();
            // 粉丝
            User followerUser = userService.findUserById(followerId);
            map.put("followerUser", followerUser);
            // 关注时间
            Double score = redisTemplate.opsForZSet().score(followerKey, followerId);
            assert score != null;
            map.put("followTime", new Date(score.longValue()));
            // 添加到粉丝列表
            list.add(map);
        }
        return list;
    }
}
